#include <iostream>
#include <sstream>
#include <map>
#include <boost/foreach.hpp>
// TODO: Depending on Qt at the moment, don't like it, should replace it with boost process at some point
#include <qprocess.h>
#include <qstringlist.h>
#include "RiskMeasureDot.h"

using namespace boost;
using namespace std;

namespace quic
{
    RiskMeasureDot::RiskMeasureDot(void)
    {
    }

    RiskMeasureDot::~RiskMeasureDot(void)
    {
    }

    QString RiskMeasureDot::renderDotGraph(shared_ptr<RiskMeasure> riskMeasure)
    {
        ofstream out(getDotPath().toStdString().c_str());
        map<string,bool> renderedNodes;
        out << "digraph riskmeasure {" << endl;
        //out << "size=\"6,6\";" << endl;
        out << "node [color=lightblue2, style=filled];" << endl;
        renderEdges(riskMeasure, out, renderedNodes);
        out << "}" << endl;
        out.close();

        QStringList args;
        args << "-o" << getImagePath() << "-Tpng" << getDotPath();

        QProcess proc;
        //proc.setStandardOutputFile("dot.stdout");
        //proc.setStandardErrorFile("dot.stderr");
        proc.start("dot", args);
        cout << "Executing: dot";
        for (QStringList::Iterator it = args.begin(); it != args.end(); ++it ) {
            cout << " " << it->toStdString();
        }
        cout << endl;
        if(!proc.waitForFinished())
            cout << "Error occured while rendering the graph" << endl;

        return getImagePath();
    }

    void RiskMeasureDot::renderEdges(shared_ptr<RiskMeasure> riskMeasure, ofstream &out,
                                     map<string,bool> &renderedNodes)
    {
        if(renderedNodes.find(riskMeasure->getName()) != renderedNodes.end())
            return;

        for(RiskMeasure::Children::iterator it = riskMeasure->children.begin();
        it != riskMeasure->children.end(); ++it)
        {
            out << "\"" << nodeIdentifier(riskMeasure) << "\" -> \""
                    << nodeIdentifier(*it) << "\";";
            renderEdges(*it, out, renderedNodes);
        }

        renderedNodes[riskMeasure->getName()] = true;
    }

    string RiskMeasureDot::nodeIdentifier(shared_ptr<RiskMeasure> riskMeasure)
    {
        ostringstream result;
        if(riskMeasure->isStored()) result << "[" << riskMeasure->getName() << "]";
        else result << riskMeasure->getName();

        result << "\\n" << riskMeasure->getModule().substr(0,riskMeasure->getModule().find("@")) << "(";
        BOOST_FOREACH( string &param, riskMeasure->parameters )
        {
            result << ' ' << param;
        }
        result << " )";

        return result.str();
    }

};
